package com.fap.search.executor.impl;

import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;

import com.fap.search.executor.DataRow;
import com.fap.search.executor.IExecutor;
import com.fap.search.meta.ParameterMeta;
import com.fap.search.meta.impl.DataMeta;
import com.fap.search.parameter.IParameter;
import com.fap.util.BeanUtil;

public class SqlExecutor implements IExecutor {

	private String _name;
	private String _sql;
	private List<ParameterMeta> _pms;
	private DataMeta _rm;
	
	private JdbcTemplate _jdbc;
	
	public SqlExecutor(String sql, List<ParameterMeta> pms, DataMeta rm){
		_sql = sql;
		_pms = pms;
		_rm = rm;
		_jdbc = (JdbcTemplate)BeanUtil.getBean(JdbcTemplate.class);
	}
	
	public String getName() {
		return _name;
	}

	public void setName(String name) {
		_name = name;
	}	
	
	private boolean checkParameter(ParameterMeta pm, IParameter p) throws Exception{
		return pm.getType().checkValue(p);
		
//		if(pm.getType() instanceof StringType && p instanceof PString)
//			return true;
//		else if(pm.getType() instanceof NumericType && p instanceof PNumeric)
//			return true;
//		else if(pm.getType() instanceof DateTimeType && p instanceof PDateTime)
//			return true;
//		else
//			return false;
	}
	
	public List<DataRow> run(IParameter[] parameters) throws Exception {
		List<Object> paramValues = new ArrayList<Object>();
		
		if(parameters!=null){
			for(int i=0; i<_pms.size(); i++){
				if(i>=parameters.length)
					throw new Exception("Executor '"+_name+"' dosn't receive enough parameters");
				
				IParameter p = parameters[i];
				
				ParameterMeta pm = _pms.get(i);
				if(checkParameter(pm,p)==false)
					throw new Exception("Executor '"+_name+"' has received invalid parameter.");
				
				paramValues.add(p.getValue());
			}
		}
		
		if(paramValues.size()>0)
			return _jdbc.query(_sql,paramValues.toArray(new Object[paramValues.size()]), resultMapper());
		else
			return _jdbc.query(_sql, resultMapper());
	}
	
	private RowMapper<DataRow> resultMapper(){
		return new RowMapper<DataRow>() {
			
			public DataRow mapRow(ResultSet rs, int rowNum) throws SQLException {
				DataRow row = new DataRow();
				ResultSetMetaData meta = rs.getMetaData();
				String col;
//				int count = meta.getColumnCount();
				for(int i=0; i<_rm.columns.size(); i++){
					col = _rm.columns.get(i);
					int index = rs.findColumn(col);
					if(index>0)
						row.put(col, rs.getString(col));
					else
						row.put(col, "");
				}
				
				return row;
			}
		};
	}

}
